package com.gopay.cashier.web.controller.T00100;

import com.gopay.common.constants.SubAccountConstants;
import com.gopay.common.cps.dao.order.CpsGeneralReceiptOrderQueryDAO;
import com.gopay.common.cps.dao.trans.CpsReceiptSplitDtlQueryDAO;
import com.gopay.common.domain.cps.CpsGenReceiptOrder;
import com.gopay.common.domain.cps.CpsReceiptSplitDtl;
import com.gopay.remote.order.Tran01813OrderCheckAndUpdateRemoteService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;

import java.math.BigDecimal;
import java.text.DecimalFormat;
import java.util.HashMap;
import java.util.Map;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;

import org.apache.commons.lang3.StringUtils;
import org.apache.shiro.SecurityUtils;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.ModelAndView;

import com.gopay.cashier.common.exception.WebException;
import com.gopay.cashier.domain.bean.LoginUser;
import com.gopay.cashier.service.CaCertService;
import com.gopay.cashier.service.CertFreeQuotaService;
import com.gopay.cashier.service.PersonUsedQuotaService;
import com.gopay.cashier.service.security.GopayDtCertService;
import com.gopay.cashier.web.command.BankPayWay;
import com.gopay.cashier.web.command.ExpressPayChannelCommand;
import com.gopay.cashier.web.command.ExpressPoundageVo;
import com.gopay.cashier.web.utils.BisBankBusinessProdConvertUtil;
import com.gopay.cashier.web.utils.CertFreeQuotaHelper;
import com.gopay.common.Result;
import com.gopay.common.cipher.utils.LoggerMaskUtils;
import com.gopay.common.constants.bank.BisBankBusinessProd;
import com.gopay.common.constants.bank.ExPayBankConstants;
import com.gopay.common.constants.cust.*;
import com.gopay.common.constants.ep.EpCardType;
import com.gopay.common.constants.microdone.EnumMicroScene;
import com.gopay.common.constants.proccode.ProcCodeConstants;
import com.gopay.common.constants.trans.*;
import com.gopay.common.constants.txncd.IntTxnCd;
import com.gopay.common.domain.UserInfo;
import com.gopay.common.domain.acps.AcctStatus;
import com.gopay.common.domain.acps.FrezCode;
import com.gopay.common.domain.acps.model.AcctMastBean;
import com.gopay.common.domain.bank.ExPayBaseMessage;
import com.gopay.common.domain.bank.PayResult;
import com.gopay.common.domain.cashier.PayDoneResult;
import com.gopay.common.domain.cashier.PayWay;
import com.gopay.common.domain.cps.CpsGenMainOrder;
import com.gopay.common.domain.cust.CustCaCert;
import com.gopay.common.domain.cust.CustCorpInfo;
import com.gopay.common.domain.cust.CustPersonInfo;
import com.gopay.common.domain.ep.EpCardBindInfo;
import com.gopay.common.domain.pg.PgGenOrderTransDtl;
import com.gopay.common.domain.poundage.PoundageRes;
import com.gopay.common.domain.user.UserPayPwdResult;
import com.gopay.common.exception.GopayException;
import com.gopay.common.proccode.DicProcCodeService;
import com.gopay.common.security.vo.DtCertCheckParamVO;
import com.gopay.common.security.vo.DtCertCheckResultVO;
import com.gopay.common.user.manager.PersonIdentifyManager;
import com.gopay.common.util.RequestUtils;
import com.gopay.remote.cps.expresspay.EpBankCardRemoteService;
import com.gopay.remote.order.MainOrderField;
import ocx.AESWithJCE;

/**
 * Created by HJY on 2015/5/11.
 * 网关支付-快捷支付
 * 支付确认 差额支付 国付宝账户支付
 */
@Controller
@RequestMapping("/sec")
public class ExpressPayConfirm00100Controller  extends ExpressBaseController {

    @Autowired
    private CpsGeneralReceiptOrderQueryDAO cpsGeneralReceiptOrderQueryDAO;

    @Autowired
    private CpsReceiptSplitDtlQueryDAO cpsReceiptSplitDtlQueryDAO;

    @Resource(name = "personIdUsedQuotaService")
    private PersonUsedQuotaService personIdUsedQuotaService;

    @Resource(name = "personIdentifyManager")
    private PersonIdentifyManager personIdentifyManager;
    
    @Resource(name = "caCertService")
    private CaCertService caCertService;
    @Resource(name="certFreeQuotaService")
    private CertFreeQuotaService certFreeQuotaService; 
    
//    @Resource(name="certCheckClient")
//    private CertCheckRemoteServiceBak certCheckClient;
    
    @Resource(name="certFreeQuotaHelper")
    private CertFreeQuotaHelper certFreeQuotaHelper;
    @Resource(name="dicProcCodeService")
    private DicProcCodeService dicProcCodeService;
    
    
    @Resource(name = "gopayDtCertService")
    private GopayDtCertService gopayDtCertService;

    @Resource(name = "epBankCardService")
    private EpBankCardRemoteService epBankCardRemoteService;


    @Resource(name = "tran01813OrderCheckAndUpdateService")
    private Tran01813OrderCheckAndUpdateRemoteService tran01813OrderCheckAndUpdateRemoteService;

    /**
     * modify by wangdong for microdone , log the user info into database
     * @author <a href="mailto:yhwpeng@126.com">wangdong</a>
     * @date 2017-01-12 16:05:56
     */
    @RequestMapping(value = "/00100/express/submit.shtml")
    public ModelAndView submit(ExpressPayChannelCommand exCommand) throws GopayException {
        decrypt4js(exCommand);
        printRequest("expressPayConfirm00100Controller-submit");
        String mcryptKey = "";
        //充值订单
        String orderId = getRequest().getParameter(GOPAY_ORDER_ID);
        LoginUser oprInfo = (LoginUser) SecurityUtils.getSubject().getPrincipal();
        String status = ProcCodeConstants.PROC_CODE_000S1000;
        String scene = EnumMicroScene.CASHIER_EXPRESS_PAY.getCode();
        if(exCommand.getExPayWay() == BankPayWay.A){
            scene = EnumMicroScene.CASHIER_BALANCE_PAY.getCode();
        }
        try {
            if(exCommand.getExPayWay() == BankPayWay.A ||StringUtils.isNotBlank(exCommand.getExCardId())){
                logger.info("需要校验密码，执行获取随机因子");
                mcryptKey = (String) getRequest().getSession().getAttribute("mcrypt_key");
                getRequest().getSession().removeAttribute("mcrypt_key");
                if(StringUtils.isBlank(mcryptKey)){
                    throw new GopayException(ProcCodeConstants.PROC_CODE_100E5120, "浏览器刷新后，请重新输入密码");
                }
                if (StringUtils.isEmpty(exCommand.getPayPassword())){
                    exCommand.setPayPassword(getRequest().getParameter("password"));
                }
            }else {
                logger.info("没有密码输入框，无需校验密码");
            }

            CpsGenMainOrder order = getMainOrder(orderId, true);
            //add by zhuliang at 2016-7-11 不是账户免验证标识，进行数字证书签名验签
            String custId = oprInfo.getUser().getCustId();
            String sign = getRequest().getParameter("sign");
            String signedData = getRequest().getParameter("signedData");
            logger.info("-----signedData----- = " + signedData);
            String  loginExFirstPay =getRequest().getParameter("loginExFirstPay");
            String exCardId = getRequest().getParameter("exCardId");
            // 只有账户支付才校验数字证书  dak.wang  20160524
            String pwd = exCommand.getPayPassword();
            //验签时需要再次判断是否免验，防止表单窜改
            BigDecimal payAmt = order.getMerTxnAmt();
            //快捷二次和个人余额支付校验数字证书动态口令 add by liuyong 20170111
            if((!"01".equals(loginExFirstPay)&&StringUtils.isNotBlank(pwd))||(exCommand.getExPayWay()== BankPayWay.A)){
                //------校验数字证书和动态口令------start    edit by fanghw 20160923
                //封装令牌和证书校验参数VO
                DtCertCheckParamVO dccParamVo = new DtCertCheckParamVO();
                dccParamVo.setUserId(oprInfo.getUser().getUserId());
                dccParamVo.setCustId(custId);
                dccParamVo.setCertSignValue(signedData);
                dccParamVo.setDtCode(getRequest().getParameter("dcpass"));
                dccParamVo.setTranAmt(payAmt);
                //校验令牌和证书
                DtCertCheckResultVO dccResultVo = gopayDtCertService.checkDtCert(getRequest(), dccParamVo);
                if (!dccResultVo.isSuccess()) {
                    throw new GopayException(dccResultVo.getErrCode(), dccResultVo.getErrMsg());
                }
            //------校验数字证书和动态口令------end
            }

            //校验当前登录用户是否通过实名认证  add by fanghw 20151113
            if(exCommand.getExPayWay() != BankPayWay.F){
                checkPayCustRealNameCertify(getLoginUser());
            }

            //系统验证
            validate(exCommand,order);

            BigDecimal tranAmt=order.getMerTxnAmt();
            //密码验证
            logger.error("快捷支付进行密码验证");
            if(!validateSubmit(exCommand,tranAmt,loginExFirstPay,mcryptKey)){
                logger.error("快捷支付进行密码验证失败，执行nex方法");
                status = exCommand.getErrMsg();
                return next(order,exCommand);
            }
            if(exCommand.getExPayWay()==BankPayWay.F){
                if("01".equals(loginExFirstPay)) {
                    //校验快捷短信验证码令牌  ,登陆首次快捷支付的时候校验短信token,不走以下验证短信逻辑
                    checkEpSmsToken(orderId, exCommand.getBankCardNo());
                }else{
                    String inputSMSCode = "请重新获取短信验证码";
                    // 快捷支付改造修改  update by dhj at 20161201 start
                    try {
                        ExPayBaseMessage message = getExPayBaseMessage(order,exCommand);
                        message.setValidateCode(exCommand.getExSmsCode());
                        message.setFailMaxCount(5);
                        message.setTimeOut("600");//短信有效期10分钟
                        //logger.info("已登录发起支付时，验短信的参数为:"+ToStringBuilder.reflectionToString(message));
                        //短信校验
                        Result result = exAuthRemoteService.checkSms(message);
                        if(result != null) {
                            String failCount = (String) result.getModel("failCount");
                            /**start ---卡号日志掩码处理 ssj 2017-04-18*/
                            logger.info("check sms orderId:" + orderId + " for mobileNo:" + LoggerMaskUtils.maskString(exCommand.getExMobileNo()) + " failCount:" + failCount + " res:" + result.isSuccess() + " resCode:" + result.getResultCode() + " retMsg:" + result.getModel("retMsg") + " resFlag:" + result.getModel("flag"));
                            /**end*/
                         
                            if (result.isSuccess()) {
                                if (((boolean) result.getModel("flag"))) {
                                    //生成快捷短信验证码令牌  add by fanghw 20160514
                                    generateEpSmsToken(orderId, message.getCardNo());

                                } else {
                                    exCommand.setErrMsg((String) result.getModel("retMsg"));
                                    exCommand.setErrId("2");
                                    status = exCommand.getErrMsg();
                                    return next(order, exCommand);
                                }
                            } else {
                                if (ProcCodeConstants.PROC_CODE_100E6103.equals(result.getResultCode())) {
                                    exCommand.setErrMsg(inputSMSCode);
                                } else {
                                    exCommand.setErrMsg(dicProcCodeService.getProcCodeInfo((String) result.getResultCode()).getMessage());
                                }
                                exCommand.setErrId("2");
                                status = exCommand.getErrMsg();
                                return next(order, exCommand);
                            }
                        }else{
                        	  /**start ---卡号日志掩码处理 ssj 2017-04-18*/
                            logger.error("check sms orderId:"+orderId+" for mobileNo:"+LoggerMaskUtils.maskString(exCommand.getExMobileNo())+" result is null ")
                            /**end*/
                           ;
                            exCommand.setErrId("1");
                            exCommand.setErrMsg("系统异常");
                            status = exCommand.getErrMsg();
                            return next(order,exCommand);
                        }
                    }catch(GopayException ex){
                        exCommand.setErrId("1");
                        exCommand.setErrMsg(dicProcCodeService.getProcCodeInfo(ex.getErrCode()).getMessage());
                        status = exCommand.getErrMsg();
                        return next(order,exCommand);
                    } catch (Exception e) {
                        logger.error("check sms orderId:"+orderId+" error:"+e.getMessage());
                        exCommand.setErrId("1");
                        exCommand.setErrMsg("系统异常");
                        status = exCommand.getErrMsg();
                        return next(order,exCommand);
                    }
                    // 快捷支付改造修改  update by dhj at 20161201 end
                }
            }
            //方案校验
            checkSolution(exCommand, order);

            //三类个人账号余额支付校验
            if(UserType.Person.value.equals(oprInfo.getUser().getUserType()) && (BankPayWay.A.equals(exCommand.getExPayWay()))){
                checkThreeAcct(oprInfo.getUser().getUserId(), oprInfo.getUser().getCustId(), order.getMerTxnAmt());
            }

            //快捷支付 身份验证  add  by dongdh  20160319
            if(exCommand.getExPayWay() != BankPayWay.A){
                //非余额全额支付  如果有上送 信息 则判断上送信息是否一致 与 是否未实名未认证
                PgGenOrderTransDtl transDtl = pgGeneralOrderTransDtlQueryManager.get(order.getTransDtlSq());
                validateExpressAuthentication(transDtl, exCommand, true);
            }
            updateOrder(exCommand,order);
            /**** add by sh.jiao 20170920 增加云账户子账户收款修改关联订单交易金额，手续费金额等字段更新逻辑 start ****/
            /*if(IntTxnCd._01813.value.equals(order.getGopayIntTxnCd())) {
                String resultCode = tran01813OrderCheckAndUpdateRemoteService.checkAndUpdateOrder(order.getGopayOrderId());
                if (!ProcCodeConstants.PROC_CODE_000S1000.equals(resultCode)) {
                    throw new GopayException(resultCode);
                }
            }*/
            /**** add by sh.jiao 20170920 增加云账户子账户收款修改关联订单交易金额，手续费金额等字段更新逻辑 end ****/

            order = getMainOrder(orderId, true);
            if(exCommand.getExPayWay() != BankPayWay.A){//非余额全额支付
                updateOrderProcess(order);
                //风控校验
                //rimsProcess(order);
                ModelAndView mv = callRiskControl(order, exCommand);
                if(mv != null){
                    status = "非余额全额支付——风控校验未通过";
                    return mv;
                }
                return bankPay(orderId,exCommand);
            }else{
                //风控校验
                //rimsProcess(order);

                //调用风控服务校验 add by fanghw 20160122
    //            callRiskControlService.transCall(order.getGopayOrderId(), order.getGopayIntTxnCd(), order.getPayChannel(),
    //                    order.getMerTxnAmt(), order.getMainRecvCustId());
                ModelAndView mv = callRiskControl(order, exCommand);
                if(mv != null){
                    status = "余额全额支付——风控校验未通过";
                    return mv;
                }

                completeOrder(order);
                return new ModelAndView("redirect:/00100/express/progress.shtml?orderKey="+getRequest().getParameter("orderKey")+"&t=0&orderId="+orderId);
            }
        } catch (GopayException e) {
            status = e.getErrMsg()==null?e.getErrCode():e.getErrMsg();
            throw e;
        }finally {
            try {
                if(exCommand.getExPayWay() == BankPayWay.A ||StringUtils.isNotBlank(exCommand.getExCardId())){
                    logger.info("需要校验密码，执行采集数据入库");
                    logMicrodone(getRequest(),mcryptKey, scene,orderId,status,oprInfo.getUser());
                }
            } catch (Exception e1) {
                logger.error("收银台快捷支付二次支付密码控件记录入库异常",e1);
            }
        }
    }

    /**
     * 登录选择卡号之后的操作跳转
     * @param exCommand
     * @return
     * @throws GopayException
     */
    @RequestMapping(value = "/00100/express/confirm.shtml")
    public ModelAndView balPay(ExpressPayChannelCommand exCommand) throws GopayException {
        if(exCommand.getExPayWay() == BankPayWay.S){
            throw new GopayException("不支持差额支付！");
        }
        printRequest("expressPayConfirm00100Controller-confirm");
        //充值订单
        String orderId = getRequest().getParameter(GOPAY_ORDER_ID);

        CpsGenMainOrder order = getMainOrder(orderId, true);

        decrypt4js(exCommand);

        // 验证
        validate(exCommand, order);

      //方案校验
        checkSolution(exCommand, order);
        
        //防钓鱼校验
        ModelAndView check = checkAntiPhish(exCommand,"/sec/00100/express/confirm.shtml?orderKey="+getRequest().getParameter("orderKey")+"&orderId="+orderId);
        if(check != null)
            return check;
        return next(order,exCommand);
    }

    private String completeOrder(CpsGenMainOrder order) throws GopayException {
        PayDoneResult r = new PayDoneResult();
        r.setSuccess(true);
        r.setPayWay(PayWay.AcctPay);
        r.setOrderId(order.getGopayOrderId());
        //支付方式
        String payType=PayAuthType.one.value;//支付密码
//        if(userDcPwdManager.getDCAuth(order.getPayCustId())){ //支付密码+其他(动态口令卡)
        if(userDcPwdManager.getDCAuthbyUserId(order.getUserId())){ //支付密码+其他(动态口令卡)
            payType=PayAuthType.three.value;
        }else{//支付密码+数字证书(电子签名)的校验
            CustCaCert custCaCert = caCertService.getCustCaCertByCustId(order.getPayCustId());
            if(null != custCaCert && CustCaCertConstants.CUST_CA_CERT_STAT_ACTIVE.equals(custCaCert.getStat())){
                payType=PayAuthType.two.value; 
            }
        }       
        r.setPayType(payType);
        String result = cashierPayCallbackService.finish(r);
        return result;
    }

    private  ModelAndView next(CpsGenMainOrder order,ExpressPayChannelCommand exCommand) throws WebException {
        try {
            prepareRSA();
        } catch (Exception e) {
            throw new WebException(ProcCodeConstants.PROC_CODE_100F1002);
        }

        ModelAndView mav = new ModelAndView("/00100/content/acct/exPayConfirm");
        BankPayWay payWay = exCommand.getExPayWay();
        mav.addObject("exPayWay",payWay.toString());
        mav.addObject("exCardId",exCommand.getExCardId());
        DecimalFormat df = new DecimalFormat("0.00");
        BigDecimal payAmt = order.getMerTxnAmt();
        if(payWay == BankPayWay.S){//差额支付
            BigDecimal bankPayAmt = getActualPayAmt(exCommand, order);
            BigDecimal acctPayAmt = order.getMerTxnAmt().subtract(bankPayAmt);
            mav.addObject("bankPayAmt", df.format(bankPayAmt));
            mav.addObject("acctPayAmt", df.format(acctPayAmt));
            mav.addObject("exPayChannel",exCommand.getExPayChannel());
            mav.addObject("exPayBankCode",exCommand.getExPayBankCode());
        }else if(payWay == BankPayWay.A){
            mav.addObject("acctPayAmt", df.format(payAmt));
        }else if(payWay == BankPayWay.F){
            BigDecimal bankPayAmt = getActualPayAmt(exCommand, order);
            mav.addObject("bankPayAmt", df.format(bankPayAmt));
            mav.addObject("exPayChannel",exCommand.getExPayChannel());
            mav.addObject("exPayBankCode",exCommand.getExPayBankCode());
        }
        if (UserType.Person == UserType.get(getLoginUser().getUser().getUserType())) {
            CustPersonInfo personInfo = custPersonInfoQueryManager.get(getLoginUser().getUser().getCustId());
            mav.addObject("isRealNameCertify", personInfo.getIsRealNameCertify());

            //未绑定卡即第一次支付时，显示注册时手机号  add by congliang ,
            if((StringUtils.isBlank(exCommand.getExCardId())||StringUtils.isBlank(exCommand.getExMobileNo()))&&payWay != BankPayWay.A){
                   exCommand.setExMobileNo(personInfo.getCustMob());
                   mav.addObject("loginExFirstPay","01");  //快捷首次支付页面判断和后台相关逻辑判断的标志
               }
            if(payWay != BankPayWay.A){
                if (UserType.Person == UserType.get(getLoginUser().getUser().getUserType())) {
                    if(!StringUtils.equals(personInfo.getIsRealNameCertify(),CustPersonInfoConstants.REAL_NAME_CERTIFY_NO)){
                        exCommand.setExHolder(personInfo.getCustName());
                        exCommand.setExIdCardNo(personInfo.getCertNo());
                    }
                }
            }
        }

        
        mav.addObject("dcErrMesg", exCommand.getDcErrMsg());

        //加上获取信用卡快捷支付的通道,二次支付并且是信用卡才去调
        String payChannel=exCommand.getExPayChannel();
        String isQueryCVN="";
        /**
         * 从bis中获取
         */
        logger.info("付款渠道:"+payChannel);
        mav.addObject("isOpendCVN2","no");
        //选择账户余额支付的时候，tab标签显示在快捷支付的界面上，会走快捷支付相关的逻辑，所以逻辑处理不完善，增加判断payWay == BankPayWay.F的方式
        if("06".equals(payChannel)&&payWay == BankPayWay.F){
        Result result = null;
        try {
			ExPayBaseMessage message = getExPayBaseMessage(order,exCommand);
			result=exAuthRemoteService.queryCvn(message);

			//空指针
//			logger.info("返回的信息:"+result.isSuccess()+"ddd"+result.getModel("isQueryCVN")+result.getModel("flag"));
		} catch (GopayException e) {
		    logger.info("调用查询CVN2码出错", e);
		}
        Boolean  flag=(Boolean) result.getModel("flag");
          if(result.isSuccess()&&flag){
        	  isQueryCVN=(String) result.getModel("isQueryCVN");
        	  //1表示需要，2表示不需要
	        if("1".equals(isQueryCVN)){
	        	logger.info("调exAuthRemoteService.queryCvn接口,返回1(需要显示CVN2)");
	        	mav.addObject("isOpendCVN2","yes");
	        	
	        }
          }else{
        	  logger.error("返回的错误信息是:"+result.getModel("retMsg"));
          } 
        }

        ///add by dongdh  20160325  身份验证版  快捷支付 
        PgGenOrderTransDtl transDtl = pgGeneralOrderTransDtlQueryManager.get(order.getTransDtlSq());
        
        if (transDtl != null) {
        	if (StringUtils.isNotEmpty(transDtl.getBuyerRealCertNo())) {
        		exCommand.setExHolder(transDtl.getBuyerRealName());
                exCommand.setExIdCardNo(transDtl.getBuyerRealCertNo());
                mav.addObject("expressReadOnly", "true");
        	}
        	 if (StringUtils.isNotEmpty(transDtl.getBuyerRealMobile())) {
             	exCommand.setExMobileNo(transDtl.getBuyerRealMobile());
             }
        }
        
        mav.addObject("payAmt", df.format(payAmt));
        mav.addObject("order", getOrderInfo(order.getGopayOrderId()));
        mav.addObject("orderId", order.getGopayOrderId());
        mav.addObject("exGopayAcctId", exCommand.getExGopayAcctId());
        mav.addObject("formhash", setReqAttr(KEY_FORM_HASH, getRandom(32)));// 防止hack
        mav.addObject("bankCardNo",exCommand.getBankCardNo());
        mav.addObject("hideBankCardNo",getHiddenCardNo(exCommand.getBankCardNo()));
        mav.addObject("hideMobileNo",getHiddenMobileNo(exCommand.getExMobileNo()));
        mav.addObject("hideExIdCardNo", getHiddenExIdCardNo(exCommand.getExIdCardNo()));
        mav.addObject("temp",exCommand);
        mav.addObject("portal_url",PORTAL_URL);
        mav.addObject("cas_server_url", CAS_URL);
        return mav;
    }

    private  ModelAndView bankPay(String orgOrderId,ExpressPayChannelCommand exCommand) throws GopayException {
        PayResult result = null;
        CpsGenMainOrder order = getMainOrder(orgOrderId, true);
        EpCardBindInfo info = bindCardInfo(exCommand, order);
        //发短信已经做过鉴权，支付的时候不需要二次鉴权，modify by liuyong 20161219
//        if (StringUtils.isNotBlank(exCommand.getExCardId())) {
//            // 二次支付,调用鉴权接口
//            Result cerResult = exAuthRemoteService.certification(getExPayBaseMessage(order,
//                    getExCommand(exCommand, info)));
//            if(cerResult != null){
//                logger.error("express bank certification orderId:"+orgOrderId+" res:"+cerResult.isSuccess()+" resCode:"+cerResult.getResultCode());
//            }
//        }

        //新额度校验前置更新银行卡号
        updatePayOrder(orgOrderId, exCommand.getBankCardNo());

        result = exPayRemoteService.pay(getPayRequest(orgOrderId,getExCommand(exCommand,info)));
        if(result != null){
            logger.info("express bank pay orderId:"+orgOrderId+" res:"+result.isSuccess()+" resCode:"+result.getResultCode());
        }

        return  new ModelAndView("redirect:/00100/express/progress.shtml?orderKey="+getRequest().getParameter("orderKey")+"&t="+(info != null ?info.getSq() : 0)+"&orderId="+orgOrderId);
    }

    private void updateOrder(ExpressPayChannelCommand command, CpsGenMainOrder order) throws WebException {
        Map<MainOrderField, String> values = new HashMap<MainOrderField, String>();
        LoginUser loginUser = getLoginUser();
        //计算手续费
        ExpressPoundageVo epv = getPoundageRes(order,command);
        PayChannel payChannel = epv.getPayChannel();
        PoundageRes p = epv.getPoundageRes();

        if(loginUser!=null){
            values.put(MainOrderField.PAY_CUST_ID, loginUser.getUser().getCustId());
            if ( PayChannel._02.value.equals(payChannel.toString()) || PayChannel._52.value.equals(payChannel.toString()) ){
                values.put(MainOrderField.PAY_ACCT, command.getExGopayAcctId());//账户支付才更新PAY_ACCT
            }
        }
        values.put(MainOrderField.PAY_CHANNEL, payChannel.value);
        values.put(MainOrderField.OUT_STLM_ID, command.getExPayBankCode());
        values.put(MainOrderField.ORDER_DEAL_AMT, p.getOrderDealAmt().toString());
        values.put(MainOrderField.ORDER_REAL_FEE_AMT, p.getOrderRealFeeAmt().toString());
        values.put(MainOrderField.TOTAL_ORDER_AMT, p.getTotalAmt().toString());
        values.put(MainOrderField.TOTAL_ORDER_FEE_AMT, p.getTotalFeeAmt().toString());
        values.put(MainOrderField.ORDER_FEE_PAYER, p.getOrderFeePayer().value);
        values.put(MainOrderField.TXN_STA_CD, TxnStaCode.TXN_STA_CD_30101.value + "");
        
        /**结算金额： 网银付款更新结算金额字段  系统加固   zhg.zhang 20160712 start**/
        values.put(MainOrderField.SETTLE_AMT, p.getSettleAmt().toPlainString());
        /**结算金额： 网银付款更新结算金额字段  系统加固   zhg.zhang 20160712 end**/

        /**远程IP地址 songefengli 20160922**/
        values.put(MainOrderField.REMOTE_IP, RequestUtils.getRemoteRealIpAddr(getRequest()));

        // 如果是收款方承担手续费，且手续费金额大于订单金额，中断交易，防止实际交易金额为负数。
        if (OrderFeePayer.REC_PAYER.equals(p.getOrderFeePayer())) {
            if (1 == p.getTotalFeeAmt().compareTo(order.getMerTxnAmt())) {
                logger.error("手续费金额大于订单金额，中断交易！pay error: feeAmt[" + p.getTotalFeeAmt() + "]>merTxnAmt["
                        + order.getMerTxnAmt() + "]! " + command + ", " + order);
                throw new WebException(ProcCodeConstants.PROC_CODE_100E5055);
            }
            /*通用分账  added by Chenyu Li at 2018/3/10 start*/
            if(isSplit(order)){
                CpsReceiptSplitDtl cpsReceiptSplitDtl = cpsReceiptSplitDtlQueryDAO.queryPlatformDtlsByGopayOrderId(order.getGopayOrderId());
                if (cpsReceiptSplitDtl == null) {
                    logger.error("平台方没有参与分账，中断交易！pay error: feeAmt[" + p.getTotalFeeAmt() + "]>merTxnAmt["
                            + order.getMerTxnAmt() + "]! " + command + ", " + order);
                    throw new WebException(ProcCodeConstants.PROC_CODE_100E1033);
                }
                if (1 == p.getTotalFeeAmt().compareTo(cpsReceiptSplitDtl.getMerTxnAmt())) {
                    logger.error("手续费金额大于平台方分账金额，中断交易！pay error: feeAmt[" + p.getTotalFeeAmt() + "]>merTxnAmt["
                            + order.getMerTxnAmt() + "]! " + command + ", " + order);
                    throw new WebException(ProcCodeConstants.PROC_CODE_100E1405);
                }
            }
            /*通用分账  added by Chenyu Li at 2018/3/10 end*/
//            BigDecimal txnAmt = order.getMerTxnAmt().subtract(p.getTotalFeeAmt());
//            BigDecimal subAccountAmt = subAccountInfoService.subAccountSumAmt(order);
//            if(subAccountAmt.compareTo(txnAmt) >0){
//                logger.error("分账总金额大于订单金额和手续费金额，中断交易！pay error: feeAmt[" + p.getTotalFeeAmt() + "]>merTxnAmt["
//                        + order.getMerTxnAmt() + "]! " +"subAccountAmt["+subAccountAmt+"]! " + command + ", " + order);
//                throw new WebException(ProcCodeConstants.PROC_CODE_100E1186);
//            }
        }

        // 云账户子账户收款交易如果普通账户可用余额小于手续费，则抛出异常，账户余额不足 add by sh.jiao 20171020
        if(IntTxnCd._01813.value.equals(order.getGopayIntTxnCd())) {
            AcctMastBean acct = acctTransService.getAccount(order.getMainRecvAcct());
            if(acct == null) {
                logger.error("收款账户不存在,gopayOrderId:"+order.getGopayOrderId());
                throw new WebException(ProcCodeConstants.PROC_CODE_100E5260);
            }
            if (new BigDecimal(acct.getAvaAmt()).compareTo(p.getTotalFeeAmt())<0){
                logger.error("手续费金额大于普通账户可用余额，中断交易，支付失败，请联系平台！pay error: feeAmt[" + p.getTotalFeeAmt() + "]>avaAmt["
                        + acct.getAvaAmt() + "]! " + command + ", " + order);
                throw new WebException(ProcCodeConstants.PROC_CODE_100E5344);
            }
        }

        try {
        	/**
    		 * modified by zyt,日志中的卡号做掩码处理，2017-1-6
    		 */
            logger.error("调用cps更新订单状态.BEGIN.call cps update mainOrder." + LoggerMaskUtils.maskString(command.toString()) + ", " + order + ", " + values);
            mainOrderUpdateService.payUpdate(order.getGopayOrderId(), values);
            /**
    		 * modified by zyt,日志中的卡号做掩码处理，2017-1-6
    		 */
            logger.error("调用cps更新订单状态.END.call cps update mainOrder." + LoggerMaskUtils.maskString(command.toString()) + ", " + order);
        } catch (GopayException e) {
        	/**
    		 * modified by zyt,日志中的卡号做掩码处理，2017-1-6
    		 */
        	logger.error("调用cps更新订单状态出错！call cps update mainOrder exception!" + LoggerMaskUtils.maskString(command.toString()) + ", " + order, e);
            throw new WebException(e.getErrCode());
        }
    }

    private void updateOrderProcess(CpsGenMainOrder order) throws WebException {
        Map<MainOrderField, String> values = new HashMap<MainOrderField, String>();
        values.put(MainOrderField.TXN_STA_CD, TxnStaCode.TXN_STA_CD_30101.value + "");
        try {
            order.setTxnStaCd(TxnStaCode.TXN_STA_CD_30101.value);
            mainOrderUpdateService.updateMany(order.getGopayOrderId(), values);
        } catch (GopayException e) {
            throw new WebException(e.getErrCode());
        }
    }


    private boolean validateSubmit(ExpressPayChannelCommand command,BigDecimal tranAmt,String loginExFirstPay,String mcryptKey) {
        String payPwd = null;
        //StringUtils.isBlank(loginExFirstPay)
        if(command.getExPayWay() == BankPayWay.A ||StringUtils.isNotBlank(command.getExCardId())){
        //快捷二次和余额支付校验密码
            try {
//                payPwd = PwdControlUtil.decryptPwd(getRequest(), command.getPayPassword());
                payPwd = AESWithJCE.getResult(mcryptKey, command.getPayPassword());//调用解密接口.获得密码明文。
            } catch (Exception e) {
                logger.error("密码解密发生错误！！ Error occurs while decrypting password!!" + command, e);
                command.setErrId("1");
                command.setErrMsg("密码解密发生错误");
                return false;
            }
            UserPayPwdResult res = userPayPwdManager.verifyPayPwd(getLoginUser().getUser().getUserId(), payPwd);
            if(res == null || !res.isVerifySuccess()){
                command.setErrMsg(res==null ? "支付密码校验失败":res.getErrorMsg());
                command.setErrId("1");
                return false;
            }
        }

        return  true;
    }


    private void validate(ExpressPayChannelCommand command, CpsGenMainOrder order) throws GopayException {
        HttpServletRequest request = getRequest();
        LoginUser loginUser = getLoginUser();
        if(loginUser == null){
            logger.error(this.getClass() + " loginUser is null " + command);
            throw new WebException(ProcCodeConstants.PROC_CODE_100W1006);
        }
        if(command.getExPayWay() != BankPayWay.A){
            if(StringUtils.isNotBlank(command.getExCardId())){
                EpCardBindInfo info = epBankCardService.getCardInfoById(command.getExCardId());
                
                
                
                if(info == null){
                    logger.error(this.getClass() + " EpCardBindInfo is null " + command);
                    throw new WebException(ProcCodeConstants.PROC_CODE_200E1001);
                }
                PayChannel cardCh = EpCardType.CREDIT == info.getBankAcctType() ? PayChannel._06 : PayChannel._03;
                if(!StringUtils.equals(command.getExPayBankCode(),info.getBankCode()) || !StringUtils.equals(command.getExPayChannel(),cardCh.value)){
                    logger.error(this.getClass() + " pay bank code  is not match " + command);
                    throw new WebException(ProcCodeConstants.PROC_CODE_200E1001);
                }
                command.setExMobileNo(info.getBindMobile());
                command.setBankCardNo(info.getBankAcctNum());

                boolean freeze = epBankCardService.isFreezeCardNo(info.getBankAcctNum());
                if(freeze){
                    logger.error(this.getClass() + info.getBankAcctNum()+" was freezed " + command);
                    throw new WebException(ProcCodeConstants.PROC_CODE_100E5118);
                }
            }else{
                command.setExCardId("");
                if (StringUtils.isBlank(command.getExPayBankCode())) {
                    logger.error(this.getClass() + "没有选择银行！ no bank selected!!" + command);
                    throw new WebException(ProcCodeConstants.PROC_CODE_200E1001);
                }
                if (StringUtils.isBlank(command.getExPayChannel())) {
                    logger.error(this.getClass() + "没有选择银行类型！ no paychannel selected!!" + command);
                    throw new WebException(ProcCodeConstants.PROC_CODE_200E1001);
                }
            }
        }

        if (null == order) {
            logger.error("找不到订单！order not exits!" + command);
            throw new WebException(ProcCodeConstants.PROC_CODE_100E5041);
        }
        if (TxnStaCode.TXN_STA_CD_30000.value != (order.getTxnStaCd())) {
            logger.error("订单状态不对！txn_sta_cd wrong!" + order);
            throw new WebException(ProcCodeConstants.PROC_CODE_100E5042);
        }
        if(StringUtils.equals(loginUser.getUser().getCustId(), order.getMainRecvCustId()) || (StringUtils.isNotBlank(command.getExGopayAcctId()) && StringUtils.equals(command.getExGopayAcctId(), order.getMainRecvAcct()))){
            throw new WebException(ProcCodeConstants.PROC_CODE_100E5011);
        }
        UserInfo userInfo = loginUser.getUser();
        if (null == userInfo || UserInfoConstants.USER_STAT_CANCEL.equals(userInfo.getUserStat())) {
            logger.error("用户不存在或尚未登录！user not exist or not login! " + request.getRemoteUser());
            throw new WebException(ProcCodeConstants.PROC_CODE_100E2001);
        }
        if (!UserInfoConstants.USER_STAT_NORMAL.equals(userInfo.getUserStat())) {
            logger.error("用户状态异常：" + userInfo.getCustId());
            throw new WebException(ProcCodeConstants.PROC_CODE_100E2002);
        }
        String userType = userInfo.getUserType();
        if (UserInfoConstants.USER_TYPE_PERSON.equals(userType)) {
            CustPersonInfo info = custPersonInfoQueryManager.get(userInfo.getCustId());
            // 状态99 并且 步骤19为假注销  dak.wang  20160530  start
//            if (info == null || CustPersonInfoConstants.CUST_STAT_CANCEL.equals(info.getCustStat())) {
            if (info == null) {
            
                throw new WebException(ProcCodeConstants.PROC_CODE_100E5001);
            }
            if (!CustPersonInfoConstants.CUST_STAT_NORMAL.equals(info.getCustStat()) 
                    && !RealNameCertifyStep.REAL_NAME_CERTIFY_STEP_19.value.equals(info.getRealNameCertifyStep())) {
                throw new WebException(ProcCodeConstants.PROC_CODE_100E5002);
            }
         // end
        } else if (userType.startsWith("2")) {
            CustCorpInfo info = custCorpInfoService.get(userInfo.getCustId());
            if (info == null || CustCorpInfoConstants.CORP_STAT_CANCEL.toString().equals(info.getCorpStat())) {
                throw new WebException(ProcCodeConstants.PROC_CODE_100E5001);
            }
            if (!CustCorpInfoConstants.CORP_STAT_NORMAL.toString().equals(info.getCorpStat())) {
                throw new WebException(ProcCodeConstants.PROC_CODE_100E5002);
            }
        } else {
            throw new WebException(ProcCodeConstants.PROC_CODE_100E1027);
        }

        //校验收款方
        checkRecvCustStatus(0, order.getMainRecvCustId());
        AcctMastBean acct = acctTransService.getAccount(order.getMainRecvAcct());
        if (null == acct) {
            logger.error("账户不存在,acctId=" + order.getMainRecvAcct());
            throw new WebException(ProcCodeConstants.PROC_CODE_100E6012);
        }
        if (AcctStatus.F.equals(acct.getAccStatus())) {
            if (FrezCode.CRE.equals(acct.getFrezCode()) || FrezCode.FUL.equals(acct.getFrezCode())) {
                throw new GopayException(ProcCodeConstants.PROC_CODE_100E3025, "账户[" + order.getMainRecvAcct()
                        + "]处于冻结状态[" + acct.getFrezCode() + "]，无法入款");
            }
        }
    }

    /**
     * 计算正确的差额支付金额，同时进行校验
     */
    private BigDecimal getActualPayAmt(ExpressPayChannelCommand command, CpsGenMainOrder order) throws WebException {
        if (command.getExPayWay() == BankPayWay.S) {
            BigDecimal orderAmt = order.getMerTxnAmt();
            AcctMastBean acct = acctTransService.getAccount(command.getExGopayAcctId());
            if (null == acct) {
                logger.error("账户不存在！acctMast not exist!" + command + ", " + order);
                throw new WebException(ProcCodeConstants.PROC_CODE_000E3001);
            }
            BigDecimal acctBalance = new BigDecimal(acct.getAvaAmt());
            //账户可用余额 + 差额支付金额 = 订单金额
            if(orderAmt.compareTo(acctBalance)==1){
                BigDecimal shortfallPayAmt = orderAmt.subtract(acctBalance);
                return shortfallPayAmt;
            }
        }
        return order.getMerTxnAmt();
    }

    private ExPayBaseMessage getExPayBaseMessage(CpsGenMainOrder order,ExpressPayChannelCommand command) throws GopayException{
        ExPayBaseMessage base = new ExPayBaseMessage();
        base.setBank(command.getExPayBankCode());
        base.setOrderId(order.getGopayOrderId());
        base.setAmount(order.getMerTxnAmt());
        base.setBankBusProd(BisBankBusinessProd._15);
        base.setMediaId(command.getExMobileNo());
        base.setCardNo(command.getBankCardNo());
        base.setCardHolder(command.getExHolder());
        base.setIdentityCode(command.getExIdCardNo());
        // 快捷支付改造修改  update by dhj at 20161201 start
        if(StringUtils.isBlank(base.getCardHolder())&&StringUtils.isBlank(base.getIdentityCode())){
        	LoginUser oprInfo = (LoginUser) SecurityUtils.getSubject().getPrincipal();
    		if(null == oprInfo){
    			logger.error("快捷支付时，session失效。。。。。。未取到登录用户信息");
    			throw new GopayException(ProcCodeConstants.PROC_CODE_100F1002);
    		}
    		String custId = oprInfo.getUser().getCustId();
    		CustPersonInfo personInfo = custPersonInfoQueryManager.get(custId);
        	base.setCardHolder(personInfo.getCustName());
        	base.setIdentityCode(personInfo.getCertNo());
        }
        // 快捷支付改造修改  update by dhj at 20161201 end
        base.setIdentityType(CustPersonInfoConstants.CERT_TYPE_IDCARD);
        if(StringUtils.equals(order.getPayChannel(),PayChannel._06.toString()) || StringUtils.equals(command.getExPayChannel(),PayChannel._06.toString())){
            base.setCvv2(command.getExCvn2());
            //二次支付查询有效期  add by liuyong
            if(StringUtils.isBlank(command.getExCardId())){
                base.setAvailableDate(command.getExValidDate());
            }else{
                EpCardBindInfo cardInfo = epBankCardRemoteService.getCardInfoById(command.getExCardId());
                base.setAvailableDate(cardInfo.getCreditCardExpired());
            }
            // end
            base.setBankOrderType(BisBankBusinessProdConvertUtil.getBisBankBusinessProd(PayChannel.get(command.getExPayChannel())).value);
            base.setBankBusProd(BisBankBusinessProd._05);
        }
        base.setBrowser(ExPayBankConstants.VAL_BROWSER_VERSION_NUMBER);
        base.setUserIp(RequestUtils.getRemoteRealIpAddr(getRequest()));
        base.setTermination(ExPayBankConstants.TERMINAL_TYPE_PC);

        //==start增加结算金额参数 add by liuyong 20170110
        ExpressPoundageVo epv = getPoundageRes(order,command);
        PoundageRes p = epv.getPoundageRes();
        base.setSettleAmt(p.getSettleAmt().toPlainString());
        //==end
        return  base;
    }
    
    //三类账号网关支付余额支付验证
    private void checkThreeAcct(String userId,String custId,BigDecimal orderAmt) throws WebException {
        String payType=PayAuthType.one.value;//支付密码
//        if(userDcPwdManager.getDCAuth(custId)){ //支付密码+其他(动态口令卡)
        if(userDcPwdManager.getDCAuthbyUserId(userId)){ //支付密码+其他(动态口令卡)
            payType=PayAuthType.three.value;
        }else{//支付密码+数字证书(电子签名)的校验
            CustCaCert custCaCert = caCertService.getCustCaCertByCustId(custId);
            if(null != custCaCert && CustCaCertConstants.CUST_CA_CERT_STAT_ACTIVE.equals(custCaCert.getStat())){
                payType=PayAuthType.two.value; 
            }
        }
        //返回处理码
        String procCode=personIdentifyManager.getIdentityLimitCheck(userId, orderAmt, payType,IntTxnCd._00100.value);
        if(!(ProcCodeConstants.PROC_CODE_200S1000.equals(procCode)))
            throw new WebException(procCode);

    }
    
}
